package universe;


import java.util.Observable;

import sound.Player;





public class Game extends Observable implements Runnable{


	private 	Board 	board;
	private 	int 	score;
	private 	int		totalLines;
	private 	int		niveau;
	private 	boolean	pause;
	private		BlockHandler	currentBlockHandler;
	private		BlockHandler	nextBlockHandler;
	private		Block	nextBlock;
	private		boolean gameOver;
	private		boolean alive = true;

	private		Player	backgroundSound;





	public Game(){
		board	= new Board(Utils.getBoardWidth(), Utils.getBoardHeight());
		score	= 0;
		totalLines = 0;
		niveau = 1;
		pause 	= false;

		nextBlock	=	Block.getRandomBlock();
		nextBlockHandler = new BlockHandler(nextBlock, this.getBoard());	

		currentBlockHandler =	new BlockHandler(Block.getRandomBlock(), this.getBoard());

		gameOver = false;

		backgroundSound = new Player(sound.Utils.gameBackgroundTone, true);
	}



	//Actions utilisateur
	public void run()
	{
		this.notifyChanges();

		int countRemovedLines = 0;
		int nbBlock = 0;
		int nbLinesInCurrentLevel = 0;

		boolean blockPushed = false;

		if(application.Utils.soundActivated){
			backgroundSound.resume();
		}

		while(!gameOver && isAlive()) {
			// traitement
			if(!pause){
				blockPushed = false;

				if(!currentBlockHandler.goDown()){
					
					board.pushBlock(currentBlockHandler.getB(), currentBlockHandler.getX(), currentBlockHandler.getY());
					nbBlock++;

					blockPushed = true;

					countRemovedLines = board.removeCompletedLines();

					if(0!=countRemovedLines){
						//System.out.println("countRemovedLines ="+countRemovedLines);
						if(countRemovedLines >=4){
							this.notifyChanges("fourLines");
						}
						else{
							this.notifyChanges("deletedLines");
						}
						
						nbLinesInCurrentLevel += countRemovedLines;
						totalLines += countRemovedLines;
						score += scoreFunction(countRemovedLines, niveau);


						if(nbLinesInCurrentLevel >= universe.Utils.nbLinesByLevel){
							universe.Utils.decrementTimerMs();
							nbLinesInCurrentLevel = 0;
							niveau++;
							this.notifyChanges("nextLevel");
						}

						//System.out.println(score);
						
					}
					else{
						this.notifyChanges("fixedBlock");
					}

					currentBlockHandler = nextBlockHandler;
					currentBlockHandler.resetClone();
					//this.notifyChanges();
					setNextBlock(Block.getRandomBlock());
					nextBlockHandler = new BlockHandler(nextBlock, this.getBoard());					


					if(!(board.pushAllowed(currentBlockHandler.getB(), currentBlockHandler.getX(), currentBlockHandler.getY())))
					{
						gameOver = true;
					}

				}
				//System.out.println(board.toString());
				this.notifyChanges();
				//System.out.println("position X"+currentBlock.getX()+"position y"+currentBlock.getY());
			}	
			try {
				// pause
				if(!blockPushed){
					//System.out.println("on sleep");
					Thread.sleep(universe.Utils.getTimerMs());
				}
				else{
					//System.out.println("on sleep pas!!!");
					//this.notifyChanges();
				}
			}
			catch (InterruptedException ex) {}		

		}
		if(gameOver && isAlive()){
			this.gameOver();	
		}
		
		//System.out.println("fin du run de la game");
	}


	public void finalize(){
		// Sauvegarde du fichier
		//FUCK OFF saveXMLFile();
		//System.out.println("dans finalize");
		try {
			super.finalize();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
		//System.out.println("fin de finalize");
	}

	private void gameOver(){
		//System.out.println("fini");
		this.currentBlockHandler.setVisible(false);

		
		
		/*if(application.Utils.soundActivated){
			System.out.println("GAME OVER");
			Player gameOverSound = new Player(sound.Utils.gameOverTone, false);
			gameOverSound.resume();
		}*/
		
		this.notifyChanges("gameOverSound");
		this.getBoard().gameOver();
		
		this.notifyChanges("GAME_OVER");
		
	}

	public void stop(){
		//this.getBackgroundSound().setAlive(false);
		//this.getBackgroundSound().stop();
		this.getBackgroundSound().killSound();
		this.finalize();
	}


	public void dropDown(){
		if(!pause && !gameOver){
			currentBlockHandler.dropDown();
			//System.out.println("on dropdown");
			this.notifyChanges();
		}
	}


	public void moveRight(){
		if(!pause && !gameOver){
			currentBlockHandler.goRight();
			this.notifyChanges();
		}
	}

	public void moveLeft(){
		if(!pause && !gameOver){
			currentBlockHandler.goLeft();
			this.notifyChanges();
		}
	}

	public void moveDown(){
		if(!pause && !gameOver){
			currentBlockHandler.goDown();
			this.notifyChanges();
		}
	}

	public void rotate(){
		if(!pause && !gameOver){
			currentBlockHandler.rotate();
			this.notifyChanges();
		}
	}




	// Getters and Setters
	public Board getBoard() {
		return board;
	}

	public void setBoard(Board board) {
		this.board = board;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public int getNblignes() {
		return totalLines;
	}

	public int getNiveau() {
		return niveau;
	}

	public boolean isGamePaused() {
		return pause;
	}

	public void togglePause() {
		this.pause = !this.pause;

		this.notifyChanges("gamePause");

	}

	public BlockHandler getCurrentBlockHandler() {
		return currentBlockHandler;
	}

	public void setCurrentBlockHandler(BlockHandler pCurrentBlockHandler) {
		this.currentBlockHandler = pCurrentBlockHandler;
	}

	/*	public BlockHandler getNextBlockHandler() {
		return nextBlockHandler;
	}*/

	/*	public void setNextBlockHandler(BlockHandler pNextBlockHandler) {
		this.nextBlockHandler = pNextBlockHandler;
	}*/

	public Block getNextBlock() {
		return nextBlock;
	}

	public void setNextBlock(Block nextBlock) {
		this.nextBlock = nextBlock;
	}


	/*	public int nbLinesToScore(int lines){
		int count=0;
		for(int i=1; i<=lines;++i){
			count+=i;
		}
		return count;
	}*/

	public int scoreFunction(int lines, int niveau){
		int points = 0;
		int returned = 0;

		if(lines == 1) points=40;
		else if(lines == 2) points=100;
		else if(lines == 3) points=300;
		else if(lines >= 4) points=1200;
		else System.out.println("problème de comptage de points car le nb de lignes supprimé est : "+lines);


		returned = (points * (niveau + 1)) + universe.Utils.getBonus();
		universe.Utils.resetBonus();

		return returned;
	}

	/*public void clear(){

		board = null;
		currentBlockHandler.clear();
		currentBlockHandler = null;
		nextBlockHandler.clear();
		nextBlockHandler = null;
		nextBlock = null;
	}*/

	private void notifyChanges(){
		this.notifyChanges("");
	}

	private void notifyChanges(String pChange){
		this.setChanged();
		this.notifyObservers(pChange);
	}


	public Player getBackgroundSound() {
		return backgroundSound;
	}


	private void setBackgroundSound(Player pBackgroundSound) {
		this.backgroundSound = pBackgroundSound;
	}

	public void reloadBackgroundSound(){
		this.setBackgroundSound(new Player(sound.Utils.gameBackgroundTone, true));
		System.out.println("on reload la musique : "+this.getBackgroundSound().getFileURL());
	}


	public boolean isAlive() {
		return alive;
	}


	public void setAlive(boolean alive) {
		this.alive = alive;
	}
}

